#ifndef __EB_GPIO_H__
#define __EB_GPIO_H__

#include <types.h>
#include <drivers/gpio_pin.h>
#include <kernel/syslog.h>
#include <config.h>


#ifndef CONFIG_GPIO_PINS
#define CONFIG_GPIO_PINS 1
#endif


/**
 * @brief GPIO configuration structure
 * @pin: GPIO pin number
 * @mux: GPIO pin mux function
 * @drv: GPIO pin drive strength
 * @dir: GPIO pin direction
 * @val: GPIO pin value
 */
struct gpio_conf {
    int16_t   pin;
    int16_t   mux;
    uint8_t   drv;
    uint8_t   dir: 4;
    uint8_t   val: 4;
};


/**
 * @brief GPIO operations structure
 * @init: Initialize GPIO pin
 * @set_clock: Set GPIO pin clock
 * @set_mux: Set GPIO pin mux function
 * @set_dir: Set GPIO pin direction
 * @set_drv: Set GPIO pin drive strength
 * @set_pulldown: Set GPIO pin pull down
 * @set_pullup: Set GPIO pin pull up
 * @set_val: Set GPIO pin value
 * @set_exit: Set GPIO pin exit function
 */
struct gpio_ops {
    void (*init)(int16_t pin);
    void (*set_clock)(int16_t pin, int status);
    void (*set_mux)(int16_t pin, uint16_t mux);
    void (*set_dir)(int16_t pin, uint8_t flag);
    void (*set_drv)(int16_t pin, uint8_t drv);
    void (*set_pulldown)(int16_t pin, uint8_t flag);
    void (*set_pullup)(int16_t pin, uint8_t flag);
    void (*set_value)(int16_t pin, uint8_t value);
    int  (*get_value)(int16_t pin);
    int  (*set_exti)(int16_t pin, int flag);
};


/**
 * @brief gpio descriptor
 * @name: gpio_desc name
 * @pin: gpio all pin number
 * @ops: gpio_ops
 * @map: gpio pin map, it used to manage gpio pin
 */
struct gpio_desc {
    /* gpio_desc name */
    const char *name;
    /* gpio_desc operation */
    struct gpio_ops *ops;
    /* all pin bit map, for busy status */
    uint8_t *map;
    /* pin count */
    const int16_t npins;
    /* refrence count */
    uint8_t ref[IO_TO_PORT(CONFIG_GPIO_PINS)];
};


#define  GPIO_SYSLOG_INFO(...)   SYSLOG_INFO("GPIO: "__VA_ARGS__)
#define  GPIO_SYSLOG_ERROR(...)  SYSLOG_ERROR("GPIO: "__VA_ARGS__)
#define  GPIO_SYSLOG_WARN(...)   SYSLOG_WARN("GPIO: "__VA_ARGS__)
#define  GPIO_DEBUG_TRACE(...)   DEBUG_TRACE("GPIO: "__VA_ARGS__)


/**
 * @brief register a gpio description(controller)
 * @param desc: gpio description
 * @return int, 0 means success, -1 means failed 
 */
int gpio_desc_register(struct gpio_desc *desc);


/**
 * @brief request GPIO pin
 * @param pin GPIO number
 * @return 0 on success, -1 on error
 */
int gpio_request(int16_t pin);


/**
 * @brief set a GPIO value
 * @param pin GPIO number
 * @param value GPIO value
 * @return none
 */
void gpio_set_value(int16_t pin, uint8_t value);


/**
 * @brief toggle a GPIO value
 * @param pin GPIO number
 * @return none
 */
void gpio_toggle_value(int16_t pin);


/**
 * @brief get a GPIO value
 * @param pin GPIO number
 * @return GPIO value
 */
int gpio_get_value(int16_t pin);


/**
 * @brief Set GPIO direction to input
 * @param pin GPIO number
 * @return 0 on success, -1 on error
 */
int gpio_direction_input(int16_t pin);


/**
 * @brief Set GPIO direction to output
 * @param pin GPIO pin number
 * @param value GPIO pin value
 */
int gpio_direction_output(int16_t pin, uint8_t value);


/**
 * @brief Set GPIO mux function
 * @param pin GPIO pin number
 * @param mux GPIO mux function
 * @return 0 on success, -1 on error
 */
int gpio_set_mux(int16_t pin, uint16_t mux);


/**
 * @brief Set GPIO pull down
 * @param pin GPIO pin number
 * @param flag GPIO pull down flag, 0: disable, 1: enable
 * @return none
 */
void gpio_set_pulldown(int16_t pin, uint8_t flag);


/**
 * @brief Set GPIO pull up
 * @param pin GPIO pin number
 * @param flag GPIO pull up flag, 0: disable, 1: enable
 * @return none
 */
void gpio_set_pullup(int16_t pin, uint8_t flag);


/**
 * @brief free a GPIO pin
 * @param pin GPIO pin number
 * @return none
 */
void gpio_free(int16_t pin);


/**
 * @brief convert GPIO pin to IRQ number
 * @param pin GPIO pin number
 * @return IRQ number
 */
int gpio_to_irq(int16_t pin, int flag);


/**
 * @brief set multiple GPIO mux function
 * @param config GPIO mux function configuration pins
 * @param npins number of pins
 * @return 0 on success, -1 on error
 */
int gpio_mux_func(const struct gpio_conf *func, int16_t npins);


/**
 * @brief free multiple GPIO mux function
 * @param config GPIO mux function configuration pins
 * @param npins number of pins
 * @return none
 */
void gpio_mux_free(const struct gpio_conf *func, int16_t npins);


/**
 * @brief Convert gpio pin to io pin
 * @param pin gpio pin number
 * @return io pin
 * @example: gpio_to_pin(75), 75 is GPIOC11, it will return 11
 */
static inline int gpio_to_pin(int16_t pin)
{
    return IO_TO_PIN(pin);
}


/**
 * @brief Convert gpio pin to io port
 * @param pin gpio pin number
 * @return io port
 * @example: gpio_to_port(75), 75 is GPIOC11, it will return 2, PA=0, PB=1, PC=2, PD=3, PE=4, ...
 */
static inline char gpio_to_port(int16_t pin)
{
    return (char)('A' + IO_TO_PORT(pin));
}


#endif // !__EB_GPIO_H__
